iT邦幫忙

2024 iThome 鐵人賽

DAY 2
0
佛心分享-刷題不只是刷題

Leecode刷題系列 第 8

D9:Q44Wildcard Matching

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240923/201693097t4F7Ko1Sq.png這題 Wildcard Matching 要實現一個字串配對的演算法,且要可支援兩種通配符:
'?':匹配任何單一字符。
'':匹配任意長度的字符序列(包括空字串)。
題目要做什麼?
要檢查字串 s 和模式 p 是不是完全匹配,且匹配要從頭到尾覆蓋整個字串。
字串與模式的遍歷:
直接比對 s 和 p 中的字符,如果模式字符是普通字母,那它就要跟字串字符完全相同。
如果模式字符是 '?',就可以匹配任何一個字符,如果模式字符是 '
',表示可以匹配0個或多個字符,這需要特別處理。
這是一個動態規劃問題,可以用一個二維的 DP 表來記錄子問題的解法,dp[i][j] 表示字串 s 的前 i 個字符是不是跟模式 p 的前 j 個字符匹配。
初始化條件:dp[0][0] 是 True,因為兩個空字串匹配,如果模式中遇到 '',要考慮 * 匹配 0 個字符或更多字符的情況。
轉移方程:
模式字符是普通字母或 '?' 時:dp[i][j] = dp[i-1][j-1],表當前字符要完全匹配或被 '?' 匹配。
當模式字符是 '
' 時:dp[i][j] = dp[i-1][j] 或 dp[i][j-1],第一種情況表示 '' 匹配了一個字符,第二種就是 '' 匹配了 0 個字符。
想法:
怎麼處理 '' 的多種匹配情況,這是這題最難的地方,因為 '' 可以匹配任意長度的字符。
邊界條件:如果模式長度是0或字串長度是0時,要特別考慮。
步驟:
動態規劃表的構建,要設置一個 DP 表,大小設 (len(s)+1) x (len(p)+1)記錄每一步的匹配結果。
狀態轉移,根據上面說的規則轉移,最後返回 dp[len(s)][len(p)]。
優化:雖然這是一個O(m*n)的問題,但大範圍匹配,可以考慮優化,像是在 * 連續匹配時減少不必要的重複計算。
程式碼:
class Solution(object):
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
#建動態規劃表,大小設 (len(s) + 1) x (len(p) + 1)
dp = [[False] * (len(p) + 1) for _ in range(len(s) + 1)]

    #初始化條件,空字串與空模式匹配
    dp[0][0] = True
    
    #初始化第一行,當模式中有 '*' 時,它可以匹配空字串
    for j in range(1, len(p) + 1):
        if p[j - 1] == '*':
            dp[0][j] = dp[0][j - 1]
    
    #填寫動態規劃表
    for i in range(1, len(s) + 1):
        for j in range(1, len(p) + 1):
            #當模式字符是 '?' 或當前字符匹配時
            if p[j - 1] == '?' or p[j - 1] == s[i - 1]:
                dp[i][j] = dp[i - 1][j - 1]
            #當模式字符是 '*' 時,有兩種選擇:
            elif p[j - 1] == '*':
                # 1. '*' 匹配了當前字符,即 dp[i - 1][j]
                #2. '*' 匹配了 0 個字符,即 dp[i][j - 1]
                dp[i][j] = dp[i - 1][j] or dp[i][j - 1]
    
    #返回最終結果
    return dp[len(s)][len(p)]

(補上 isMatch 函數)
困難點:
主要挑戰在 匹配'' ,'' 可以配任意長度的字符,所以要考慮兩種情況:
'' 匹配了當前字符,繼續往下配下一個字。
'
' 匹配 0 個字符,那就忽略當前的 '*' 繼續配剩下的部分。
處理空字串或者模式只有 * 的情況,還有當 p 中沒有 * 的時候字串長度是不是一樣。

步驟解釋:
動態規劃表的初始化,建了一個 dp 表,dp[i][j] 表 s 的前 i 個字符是不是跟 p 的前 j 個字符匹配,dp[0][0] = True 表空字串和空模式匹配,當
如果模式中出現 '' 時,dp[0][j] 也有可能為是True,因為 '' 可以匹配空字串。
填充動態規劃表,如果當前模式字符是 '?' 或跟 s[i-1] 字符一樣,就dp[i][j] = dp[i-1][j-1],如果模式字符是 '*',就要考慮兩種情況,

  • 匹配了一個字符,則 dp[i][j] = dp[i-1][j]。
  • 匹配 0 個字符,則 dp[i][j] = dp[i][j-1]。
    最後,dp[len(s)][len(p)] 表整個字串和模式是不是完全匹配,這個解用動態規劃的技巧,可以有效地解決模式匹配中的各種特殊情況,尤其是 '*' 和 '?' 。

上一篇
D8:Q38Count and Say
下一篇
D10:Q46Permutations
系列文
Leecode刷題10
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言